package com.vhans.db.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.vhans.core.domain.BQuiz;
import com.vhans.core.domain.BRecord;
import com.vhans.core.domain.SiteConfig;
import com.vhans.core.redis.RedisService;
import com.vhans.core.utils.IpUtils;
import com.vhans.core.utils.UserAgentUtils;
import com.vhans.db.mapper.*;
import com.vhans.db.model.vo.WebsiteHomeInfoVO;
import com.vhans.db.model.vo.WebsiteInfoVO;
import com.vhans.db.model.vo.log.UserViewVO;
import com.vhans.db.model.vo.quiz.QuizRankVO;
import com.vhans.db.model.vo.quiz.QuizStatisticsVO;
import com.vhans.db.model.vo.record.RecordRankVO;
import com.vhans.db.model.vo.record.RecordStatisticsVO;
import com.vhans.db.model.vo.tag.TagOptionVO;
import com.vhans.db.service.SiteConfigService;
import com.vhans.db.service.WebsiteInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.vhans.core.constant.CommonConstant.FALSE;
import static com.vhans.core.constant.RedisConstant.*;
import static com.vhans.core.enums.QuizStatusEnum.PASS;
import static com.vhans.core.enums.RecordStatusEnum.PUBLIC;

/**
 * 博客业务接口实现类
 *
 * @author vhans
 **/
@Service
public class WebsiteInfoServiceImpl implements WebsiteInfoService {

    @Autowired
    private BRecordMapper recordMapper;

    @Autowired
    private BQuizMapper quizMapper;

    @Autowired
    private BTagMapper tagMapper;

    @Autowired
    private BUserMapper userMapper;

    @Autowired
    private AVisitLogMapper visitLogMapper;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private RedisService redisService;

    @Autowired
    private SiteConfigService siteConfigService;

    @Override
    public void report() {
        // 获取用户ip
        String ipAddress = IpUtils.getIpAddress(request);
        Map<String, String> userAgentMap = UserAgentUtils.parseOsAndBrowser(request.getHeader("User-Agent"));
        // 获取访问设备
        String browser = userAgentMap.get("browser");
        String os = userAgentMap.get("os");
        // 生成唯一用户标识
        String uuid = ipAddress + browser + os;
        String md5 = DigestUtils.md5DigestAsHex(uuid.getBytes());
        // 判断是否访问
        if (!redisService.hasSetValue(UNIQUE_VISITOR, md5)) {
            // 访问量+1
            redisService.incr(WEBSITE_VIEW_COUNT, 1);
            // 保存唯一标识
            redisService.setSet(UNIQUE_VISITOR, md5);
        }
    }

    @Override
    public WebsiteHomeInfoVO getWebsiteHomeInfo() {
        // 记录数量
        Long recordCount = recordMapper.selectCount(new LambdaQueryWrapper<BRecord>()
                .eq(BRecord::getStatus, PUBLIC.getStatus()).eq(BRecord::getIsDelete, FALSE));
        // 题目数量
        Long quizCount = quizMapper.selectCount(new LambdaQueryWrapper<BQuiz>()
                .eq(BQuiz::getIsCheck, PASS.getStatus()));
        // 标签数量
        Long tagCount = tagMapper.selectCount(null);
        // 网站访问量
        Integer count = redisService.getObject(WEBSITE_VIEW_COUNT);
        String viewCount = Optional.ofNullable(count).orElse(0).toString();
        // 网站配置
        SiteConfig siteConfig = siteConfigService.getSiteConfig();
        return WebsiteHomeInfoVO.builder()
                .recordCount(recordCount)
                .quizCount(quizCount)
                .tagCount(tagCount)
                .viewCount(viewCount)
                .siteConfig(siteConfig)
                .build();
    }

    @Override
    public WebsiteInfoVO getWebsiteInfo() {
        // 访问量
        Integer viewCount = redisService.getObject(WEBSITE_VIEW_COUNT);
        // 用户量
        Long userCount = userMapper.selectCount(null);
        // 记录量
        Long recordCount = recordMapper.selectCount(new LambdaQueryWrapper<BRecord>()
                .eq(BRecord::getIsDelete, FALSE));
        // 题目量
        Long quizCount = quizMapper.selectCount(new LambdaQueryWrapper<BQuiz>()
                .eq(BQuiz::getIsCheck, PASS.getStatus()));
        // 标签数据
        List<TagOptionVO> tagVOList = tagMapper.selectTagOptionList();
        // 查询前七天用户浏览
        DateTime startTime = DateUtil.beginOfDay(DateUtil.offsetDay(new Date(), -7));
        DateTime endTime = DateUtil.endOfDay(new Date());
        List<UserViewVO> userViewVOList = visitLogMapper.selectUserViewList(startTime, endTime);
        // 记录统计
        List<RecordStatisticsVO> recordStatisticsList = recordMapper.selectRecordStatistics();
        // 题目统计
        List<QuizStatisticsVO> quizStatisticsList = quizMapper.selectQuizStatistics();
        // 查询访问量前五的记录
        Map<Object, Double> recordMap = redisService.zReverseRangeWithScore(RECORD_VIEW_COUNT, 0, 4);
        // 查询访问量前五的题目
        Map<Object, Double> quizMap = redisService.zReverseRangeWithScore(QUIZ_VIEW_COUNT, 0, 4);
        WebsiteInfoVO websiteInfoVO = WebsiteInfoVO.builder()
                .tagVOList(tagVOList)
                .viewCount(viewCount)
                .userCount(userCount)
                .recordCount(recordCount)
                .quizCount(quizCount)
                .recordStatisticsList(recordStatisticsList)
                .quizStatisticsList(quizStatisticsList)
                .userViewVOList(userViewVOList)
                .build();
        if (CollectionUtils.isNotEmpty(recordMap)) {
            // 查询记录排行
            List<RecordRankVO> recordRankVOList = listRecordRank(recordMap);
            websiteInfoVO.setRecordRankVOList(recordRankVOList);
            // 查询题目排行
            List<QuizRankVO> quizRankVOList = listQuizRank(quizMap);
            websiteInfoVO.setQuizRankVOList(quizRankVOList);
        }
        return websiteInfoVO;
    }

    @Override
    public String getAbout() {
        SiteConfig siteConfig = redisService.getObject(SITE_SETTING);
        return siteConfig.getAboutMe();
    }

    /**
     * 查询记录排行
     *
     * @param recordMap 记录浏览量信息
     * @return {@link List<RecordRankVO>} 记录排行
     */
    private List<RecordRankVO> listRecordRank(Map<Object, Double> recordMap) {
        // 提取记录id
        List<Integer> recordIdList = new ArrayList<>(recordMap.size());
        recordMap.forEach((key, value) -> recordIdList.add((Integer) key));
        // 查询记录信息
        List<BRecord> recordList = recordMapper.selectList(new LambdaQueryWrapper<BRecord>()
                .select(BRecord::getId, BRecord::getTitle)
                .in(BRecord::getId, recordIdList));
        return recordList.stream()
                .map(record -> RecordRankVO.builder()
                        .recordTitle(record.getTitle())
                        .viewCount(recordMap.get(record.getId()).intValue())
                        .build())
                .sorted(Comparator.comparingInt(RecordRankVO::getViewCount).reversed())
                .toList();
    }

    /**
     * 查询题目排行
     *
     * @param quizMap 题目浏览量信息
     * @return {@link List<QuizRankVO>} 题目排行
     */
    private List<QuizRankVO> listQuizRank(Map<Object, Double> quizMap) {
        // 提取记录id
        List<Integer> quizIdList = new ArrayList<>(quizMap.size());
        quizMap.forEach((key, value) -> quizIdList.add((Integer) key));
        // 查询记录信息
        List<BQuiz> quizList = quizMapper.selectList(new LambdaQueryWrapper<BQuiz>()
                .select(BQuiz::getId, BQuiz::getTitle)
                .in(BQuiz::getId, quizIdList));
        return quizList.stream()
                .map(quiz -> QuizRankVO.builder()
                        .quizTitle(quiz.getTitle())
                        .viewCount(quizMap.get(quiz.getId()).intValue())
                        .build())
                .sorted(Comparator.comparingInt(QuizRankVO::getViewCount).reversed())
                .toList();
    }
}
